/*
    YmsgIRC - Program enabling YMSG chat clients to use IRC
    Copyright (C) 2011 Crash Daemonicus ( crashenator -at- gmail.com )

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "Proxy.h"



Proxy::Proxy(){
    dbg_head("Proxy()");
    irc.init();
    ymsg.init(17,0,0);
    networks[NETWORK_IRC]=&irc;
    networks[NETWORK_YMSG]=&ymsg;
    dbg_foot(0);
}
bool Proxy::Startup(){
    dbg_head("Proxy::Startup()");
    XSADATA xsaData;
    if(XSAStartup(MAKEWORD(2, 0), &xsaData) != 0){ puts("***Startup failed!");ReturnD(false);}
    //irc=new IRC();
    //ymsg=new YMSG(17,0,0);;
    
    
    ReturnD(true);
}

bool Proxy::Shutdown(){
    dbg_head("Proxy::Shutdown()");
    //delete irc;
    //delete ymsg;
    ReturnD(XSACleanup() == 0);
}



void Proxy::notifyState(const string& state)
{
    for(int i=0;i<Proxy::iNetworks;i++) networks[i]->notifyStateText(state);
    //ymsg->notifyStateText(state);
    //irc->notifyStateText(state);//which is discarded anyway at this time.
}
void Proxy::translateName(string& name,NwCheckType fromCheck,const NwNetwork& to,NetworkType typeTo)
{
    switch(fromCheck)
    {
        case NW_CHECK_USERNAME:
            name=to.username;
            break;
        case NW_CHECK_CHANNEL:
            name=to.channel.name;
            break;
        /*case NW_CHECK_CHANNEL_UNKNOWN:
        case NW_CHECK_RESERVED://stays the same
        case NW_CHECK_UNKNOWN:
        case NW_CHECK_INVALID:
        case NW_CHECK_BLANK:
            break;*/
    }
}

bool Proxy::translateEvent(NwNotify& n,NwNetwork& from, NwNetwork& to,NetworkType typeFrom,NetworkType typeTo)
{
    bool relayMsg=true;
    switch(n.typ)
    {
        case NW_ULIST_APPEND:
        case NW_ULIST_REMOVE:
        case NW_PRIVMSG:
        case NW_CHATMSG:
            translateName(n.sDat[0],n.cDat[0],to,typeTo);
            translateName(n.sDat[1],n.cDat[1],to,typeTo);
			if(typeFrom==NETWORK_YMSG){
				stringreplace(n.sDat[2],"\r"," ");
				stringreplace(n.sDat[2],"\n"," ");
			}
            break;
        case NW_USERNAME:
        case NW_ULIST_TOPIC:
            translateName(n.sDat[0],n.cDat[0],to,typeTo);
            break;
        case NW_LOGOUT:
            if(typeFrom==NETWORK_IRC){
                notifyState("IRC Logged Out");
                to.actions.push(NwNotify(NW_DISCONNECT));
                relayMsg=false;
            }
            break;
        case NW_DISCONNECT:
            if(typeFrom==NETWORK_IRC){ notifyState("IRC Disconnected");}
            to.actions.push(NwNotify(NW_LOGOUT));
            to.actions.push(NwNotify(NW_DISCONNECT));
            relayMsg=false;
            break;
        case NW_CONNECT:
            if(typeFrom==NETWORK_IRC){ notifyState("IRC Connected"); relayMsg=false;}
            break;
        case NW_LOGIN:
            if(typeFrom==NETWORK_IRC){ notifyState("IRC Logged In"); relayMsg=false;}
            break;
        case NW_ULIST_START:
        case NW_ULIST_NAME:
        case NW_PASSWORD:
        case NW_ULIST_END:
        case NW_DATA:
        default://default stepAction
            break;
    }
    return relayMsg;
}

bool Proxy::eventsAvailable()
{
    return ( networks[0]->events.size()>0 || networks[1]->events.size()>0);
}
void Proxy::stepEvents()
{
    if(networks[0]->events.size()>0){
        NwNotify n=networks[0]->events.front();
        puts(    networks[0]->name + ":E:" + NwNotifyType_Debug(n.typ)
                +" "+n.sDat[0]+" "+n.sDat[1]+" "+n.sDat[2]
        );
        if(translateEvent(n,*networks[0], *networks[1],(NetworkType)0,(NetworkType)1)){
            networks[1]->actions.push(n);
        }
        networks[0]->events.pop();
    }
    if(networks[1]->events.size()>0){
        NwNotify n=networks[1]->events.front();
        puts(networks[1]->name + ":E:" + NwNotifyType_Debug(n.typ)
            +" "+n.sDat[0]+" "+n.sDat[1]+" "+n.sDat[2]
        );
        if(translateEvent(n,*networks[1], *networks[0],(NetworkType)1,(NetworkType)0)){
            networks[0]->actions.push(n);
        }
        networks[1]->events.pop();
    }
}

void Proxy::stepNetworks(NwStepState state)
{
    // this is a workaround
    // because the Steps are overloaded virtuals in child classes,
    //they must be called as casted to child classes
    ymsg.step(state);
    irc.step(state);
    //for(int i=0;i<Proxy::iNetworks;i++) networks[i].step(NW_STEP);// <-- only calls base class methods
}
int Proxy::step()
{
    while(eventsAvailable()) stepEvents();
    stepNetworks(NW_STEP);
    return 0;//***change: check step for errors; decide on  error output values
}
bool Proxy::stepsBegin()
{
    dbg_head("Proxy::stepsBegin()");
    stepNetworks(NW_STEP_BEGIN);
    ReturnD(true);
}
void Proxy::stepsEnd()
{
    dbg_head("Proxy::stepsEnd()");
    stepNetworks(NW_STEP_END);
    dbg_foot(0);
}
